import sqlite3
import pandas as pd
import numpy as np
from collections import Counter
import random
from datetime import datetime

class DLTPredictor:
    def __init__(self):
        self.conn = sqlite3.connect('lottery.db')
        self.recent_draws = 100  # 分析最近100期数据
        self.front_balls_range = range(1, 36)  # 前区范围1-35
        self.back_balls_range = range(1, 13)  # 后区范围1-12
        
    def get_historical_data(self):
        """获取历史开奖数据"""
        query = """
            SELECT draw_num, draw_date, 
                   red_ball_1, red_ball_2, red_ball_3, red_ball_4, red_ball_5, 
                   blue_ball_1, blue_ball_2
            FROM dlt_draws
            ORDER BY draw_num DESC
            LIMIT ?
        """
        
        df = pd.read_sql_query(query, self.conn, params=(self.recent_draws,))
        return df
    
    def analyze_frequency(self, df):
        """分析号码出现频率"""
        # 前区频率分析
        front_balls = []
        for i in range(1, 6):
            front_balls.extend(df[f'red_ball_{i}'].tolist())
        
        front_freq = Counter(front_balls)
        for num in self.front_balls_range:
            if num not in front_freq:
                front_freq[num] = 0
        
        # 后区频率分析
        back_balls = []
        for i in range(1, 3):
            back_balls.extend(df[f'blue_ball_{i}'].tolist())
        
        back_freq = Counter(back_balls)
        for num in self.back_balls_range:
            if num not in back_freq:
                back_freq[num] = 0
        
        return front_freq, back_freq
    
    def analyze_hot_cold(self, front_freq, back_freq):
        """分析冷热号"""
        # 按频率排序
        sorted_front = sorted(front_freq.items(), key=lambda x: x[1], reverse=True)
        sorted_back = sorted(back_freq.items(), key=lambda x: x[1], reverse=True)
        
        # 热号(出现频率前1/3)
        hot_front = [num for num, _ in sorted_front[:12]]
        hot_back = [num for num, _ in sorted_back[:4]]
        
        # 温号(出现频率中间1/3)
        warm_front = [num for num, _ in sorted_front[12:24]]
        warm_back = [num for num, _ in sorted_back[4:8]]
        
        # 冷号(出现频率后1/3)
        cold_front = [num for num, _ in sorted_front[24:]]
        cold_back = [num for num, _ in sorted_back[8:]]
        
        return {
            'hot_front': hot_front,
            'warm_front': warm_front,
            'cold_front': cold_front,
            'hot_back': hot_back,
            'warm_back': warm_back,
            'cold_back': cold_back
        }
    
    def analyze_missing_values(self, df):
        """分析遗漏值"""
        # 获取最近一期的期号
        latest_draw_num = df['draw_num'].iloc[0]
        
        # 初始化遗漏值字典
        front_missing = {num: 0 for num in self.front_balls_range}
        back_missing = {num: 0 for num in self.back_balls_range}
        
        # 计算每个号码的遗漏值
        for _, row in df.iterrows():
            front_numbers = [row[f'red_ball_{i}'] for i in range(1, 6)]
            back_numbers = [row[f'blue_ball_{i}'] for i in range(1, 3)]
            
            # 更新已出现号码的遗漏值为0
            for num in front_numbers:
                if front_missing[num] != -1:  # -1表示已经计算过遗漏值
                    front_missing[num] = -1
            
            for num in back_numbers:
                if back_missing[num] != -1:
                    back_missing[num] = -1
            
            # 增加未出现号码的遗漏值
            for num in self.front_balls_range:
                if front_missing[num] != -1:
                    front_missing[num] += 1
            
            for num in self.back_balls_range:
                if back_missing[num] != -1:
                    back_missing[num] += 1
        
        # 移除-1标记
        for num in self.front_balls_range:
            if front_missing[num] == -1:
                front_missing[num] = 0
        
        for num in self.back_balls_range:
            if back_missing[num] == -1:
                back_missing[num] = 0
        
        return front_missing, back_missing
    
    def analyze_sum_and_distribution(self, df):
        """分析和值与分布"""
        # 计算前区和值
        df['front_sum'] = df.apply(lambda row: sum(row[f'red_ball_{i}'] for i in range(1, 6)), axis=1)
        
        # 计算前区奇偶比
        df['front_odd_count'] = df.apply(lambda row: sum(1 for i in range(1, 6) if row[f'red_ball_{i}'] % 2 == 1), axis=1)
        df['front_even_count'] = 5 - df['front_odd_count']
        
        # 计算前区大小比(1-18为小号，19-35为大号)
        df['front_small_count'] = df.apply(lambda row: sum(1 for i in range(1, 6) if row[f'red_ball_{i}'] <= 18), axis=1)
        df['front_big_count'] = 5 - df['front_small_count']
        
        # 计算前区区间分布(1-12,13-24,25-35)
        df['front_zone1_count'] = df.apply(lambda row: sum(1 for i in range(1, 6) if 1 <= row[f'red_ball_{i}'] <= 12), axis=1)
        df['front_zone2_count'] = df.apply(lambda row: sum(1 for i in range(1, 6) if 13 <= row[f'red_ball_{i}'] <= 24), axis=1)
        df['front_zone3_count'] = df.apply(lambda row: sum(1 for i in range(1, 6) if 25 <= row[f'red_ball_{i}'] <= 35), axis=1)
        
        # 统计分析结果
        sum_stats = {
            'front_sum_mean': df['front_sum'].mean(),
            'front_sum_median': df['front_sum'].median(),
            'front_sum_min': df['front_sum'].min(),
            'front_sum_max': df['front_sum'].max(),
            'odd_even_ratio': df.groupby(['front_odd_count', 'front_even_count']).size().sort_values(ascending=False).head(3).to_dict(),
            'big_small_ratio': df.groupby(['front_small_count', 'front_big_count']).size().sort_values(ascending=False).head(3).to_dict(),
            'zone_distribution': df.groupby(['front_zone1_count', 'front_zone2_count', 'front_zone3_count']).size().sort_values(ascending=False).head(3).to_dict()
        }
        
        return sum_stats
    
    def analyze_consecutive_numbers(self, df):
        """分析连号情况"""
        consecutive_counts = []
        
        for _, row in df.iterrows():
            front_numbers = sorted([row[f'red_ball_{i}'] for i in range(1, 6)])
            count = 0
            for i in range(len(front_numbers) - 1):
                if front_numbers[i+1] - front_numbers[i] == 1:
                    count += 1
            consecutive_counts.append(count)
        
        consecutive_stats = Counter(consecutive_counts)
        return consecutive_stats
    
    def generate_predictions(self, count=10):
        """生成预测号码"""
        df = self.get_historical_data()
        front_freq, back_freq = self.analyze_frequency(df)
        hot_cold_analysis = self.analyze_hot_cold(front_freq, back_freq)
        front_missing, back_missing = self.analyze_missing_values(df)
        sum_stats = self.analyze_sum_and_distribution(df)
        consecutive_stats = self.analyze_consecutive_numbers(df)
        
        # 打印分析结果
        print("=== 大乐透号码预测分析 ===\n")
        print(f"分析基于最近{self.recent_draws}期开奖数据")
        print(f"当前日期: {datetime.now().strftime('%Y-%m-%d')}\n")
        
        print("前区热号(高频号码):", hot_cold_analysis['hot_front'])
        print("前区温号(中频号码):", hot_cold_analysis['warm_front'])
        print("前区冷号(低频号码):", hot_cold_analysis['cold_front'])
        print("\n后区热号:", hot_cold_analysis['hot_back'])
        print("后区温号:", hot_cold_analysis['warm_back'])
        print("后区冷号:", hot_cold_analysis['cold_back'])
        
        print("\n前区遗漏值前10名:")
        sorted_front_missing = sorted(front_missing.items(), key=lambda x: x[1], reverse=True)[:10]
        for num, missing in sorted_front_missing:
            print(f"号码 {num}: 遗漏{missing}期")
        
        print("\n后区遗漏值前5名:")
        sorted_back_missing = sorted(back_missing.items(), key=lambda x: x[1], reverse=True)[:5]
        for num, missing in sorted_back_missing:
            print(f"号码 {num}: 遗漏{missing}期")
        
        print(f"\n前区和值统计: 平均值 {sum_stats['front_sum_mean']:.2f}, 中位数 {sum_stats['front_sum_median']}, 范围 {sum_stats['front_sum_min']}-{sum_stats['front_sum_max']}")
        
        print("\n最常见的奇偶比例:")
        for (odd, even), count in list(sum_stats['odd_even_ratio'].items())[:3]:
            print(f"奇数{odd}个:偶数{even}个 - 出现{count}次")
        
        print("\n最常见的大小比例:")
        for (small, big), count in list(sum_stats['big_small_ratio'].items())[:3]:
            print(f"小号{small}个:大号{big}个 - 出现{count}次")
        
        print("\n最常见的区间分布:")
        for (zone1, zone2, zone3), count in list(sum_stats['zone_distribution'].items())[:3]:
            print(f"前区{zone1}个:中区{zone2}个:后区{zone3}个 - 出现{count}次")
        
        print("\n连号统计:")
        for consec_count, freq in sorted(consecutive_stats.items()):
            print(f"{consec_count}组连号: 出现{freq}次")
        
        # 获取最常见的奇偶比例和大小比例
        common_odd_even = list(sum_stats['odd_even_ratio'].keys())[0]
        common_big_small = list(sum_stats['big_small_ratio'].keys())[0]
        common_zone_dist = list(sum_stats['zone_distribution'].keys())[0]
        
        # 生成预测号码
        predictions = []
        for _ in range(count):
            valid_combination = False
            attempts = 0
            
            while not valid_combination and attempts < 10:
                attempts += 1
                # 根据分析结果生成前区号码
                front_candidates = set()
                
                # 加入一些热号
                front_candidates.update(random.sample(hot_cold_analysis['hot_front'], k=min(2, len(hot_cold_analysis['hot_front']))))
                
                # 加入一些温号
                front_candidates.update(random.sample(hot_cold_analysis['warm_front'], k=min(1, len(hot_cold_analysis['warm_front']))))
                
                # 加入一些遗漏值较高的号码
                high_missing_fronts = [num for num, _ in sorted_front_missing[:5]]
                front_candidates.update(random.sample(high_missing_fronts, k=min(1, len(high_missing_fronts))))
                
                # 如果不足5个，从剩余号码中随机选择
                remaining_count = 5 - len(front_candidates)
                if remaining_count > 0:
                    remaining_numbers = list(set(self.front_balls_range) - front_candidates)
                    front_candidates.update(random.sample(remaining_numbers, k=remaining_count))
                
                # 确保只有5个前区号码
                if len(front_candidates) > 5:
                    front_candidates = set(random.sample(list(front_candidates), k=5))
                
                # 转换为列表并排序
                front_candidates = sorted(list(front_candidates))
                
                # 验证组合是否符合常见模式
                odd_count = sum(1 for num in front_candidates if num % 2 == 1)
                even_count = 5 - odd_count
                
                small_count = sum(1 for num in front_candidates if num <= 18)
                big_count = 5 - small_count
                
                zone1_count = sum(1 for num in front_candidates if 1 <= num <= 12)
                zone2_count = sum(1 for num in front_candidates if 13 <= num <= 24)
                zone3_count = sum(1 for num in front_candidates if 25 <= num <= 35)
                
                # 计算连号数
                consecutive_count = 0
                for i in range(len(front_candidates) - 1):
                    if front_candidates[i+1] - front_candidates[i] == 1:
                        consecutive_count += 1
                
                # 计算和值
                front_sum = sum(front_candidates)
                
                # 检查是否符合常见模式
                if (abs(odd_count - common_odd_even[0]) <= 1 and 
                    abs(small_count - common_big_small[0]) <= 1 and 
                    abs(zone1_count - common_zone_dist[0]) <= 1 and 
                    abs(zone2_count - common_zone_dist[1]) <= 1 and 
                    abs(zone3_count - common_zone_dist[2]) <= 1 and 
                    consecutive_count in [0, 1, 2] and 
                    sum_stats['front_sum_min'] <= front_sum <= sum_stats['front_sum_max']):
                    valid_combination = True
            
            # 生成后区号码
            back_candidates = []
            
            # 有70%的概率选择热门后区号码
            if random.random() < 0.7:
                back_candidates.extend(hot_cold_analysis['hot_back'])
            else:
                # 有30%的概率选择遗漏值高的后区号码
                high_missing_backs = [num for num, _ in sorted_back_missing[:3]]
                back_candidates.extend(high_missing_backs)
            
            # 如果没有候选后区号码，从所有后区号码中随机选择
            if not back_candidates:
                back_candidates = list(self.back_balls_range)
            
            # 确保有足够的候选号码
            if len(back_candidates) < 2:
                additional_numbers = list(set(self.back_balls_range) - set(back_candidates))
                back_candidates.extend(random.sample(additional_numbers, k=min(2, len(additional_numbers))))
            
            # 选择2个后区号码
            back_balls = sorted(random.sample(back_candidates, k=min(2, len(back_candidates))))
            
            # 添加到预测结果
            predictions.append((front_candidates, back_balls))
        
        print("\n=== 推荐号码组合 ===\n")
        for i, (fronts, backs) in enumerate(predictions, 1):
            front_str = ' '.join(str(num).zfill(2) for num in fronts)
            back_str = ' '.join(str(num).zfill(2) for num in backs)
            print(f"组合{i}: 前区: {front_str} | 后区: {back_str}")
        
        # 额外推荐一个胆拖方案
        print("\n=== 胆拖推荐 ===\n")
        # 选择2-3个胆码(从热号中选择)
        dan_count = random.randint(1, 2)
        dan = random.sample(hot_cold_analysis['hot_front'][:8], k=dan_count)
        # 选择6-8个拖码
        tuo_count = random.randint(6, 8)
        tuo_candidates = list(set(self.front_balls_range) - set(dan))
        tuo = random.sample(tuo_candidates, k=tuo_count)
        # 选择后区号码
        back_dan = random.sample(hot_cold_analysis['hot_back'], k=min(2, len(hot_cold_analysis['hot_back'])))
        back_tuo = random.sample(hot_cold_analysis['warm_back'], k=min(2, len(hot_cold_analysis['warm_back'])))
        
        print(f"前区胆码: {' '.join(str(num).zfill(2) for num in sorted(dan))}")
        print(f"前区拖码: {' '.join(str(num).zfill(2) for num in sorted(tuo))}")
        print(f"后区胆码: {' '.join(str(num).zfill(2) for num in sorted(back_dan))}")
        print(f"后区拖码: {' '.join(str(num).zfill(2) for num in sorted(back_tuo))}")
        
        return predictions

if __name__ == "__main__":
    predictor = DLTPredictor()
    predictor.generate_predictions(5)